package rensoft.android.rpc.simpleserver;

import static rensoft.android.lang.AndroidLang.event;
import static rensoft.android.lang.AndroidLang.sleep;
import static rensoft.java.lang.Lang.error;
import static rensoft.java.lang.Lang.is;
import static rensoft.java.lang.Lang.json;
import static rensoft.java.lang.Lang.no;

import rensoft.android.lang.AndroidLang;
import rensoft.android.lang.IAplication;
import rensoft.android.lang.RequestBase;
import rensoft.android.rpc.IServerRequest;
import rensoft.java.event.Event;
import rensoft.java.json.JSONObject;
import rensoft.java.lang.Lang;
import rensoft.java.lang.Run;
import rensoft.java.net.UrlBuilder;

public class ServerRequest extends RequestBase implements IServerRequest {

  private static final String EXCEPTION_ID = "exception";
  private static final String EXCEPTION_SESSION_EXPIRED = "session_expired";

  protected JSONObject data;
  private String action;
  protected boolean canceled;

  private boolean failed;
  private boolean loaded;
  private String exceptionMessage;
  private String exceptionDetails;
  private final IAplication application = AndroidLang.getAplication();
  private final Event<UrlBuilder> urlCreateEvent = event();
  private boolean done = false;
  private final ISimpleRpcServer server;

  public ServerRequest(ISimpleRpcServer server, String action) {
    this.server = server;
    this.action = action;
    add("action", action);
  }

  public String getAction() {
    return action;
  }

  public String getData(String key) {
    return data.getString(key);
  }

  public Event<UrlBuilder> getEventUrlCreate() {
    return urlCreateEvent;
  }

  public String getExceptionDetails() {
    return exceptionDetails;
  }

  public String getExceptionMessage() {
    return exceptionMessage;
  }

  public String getMessageId() {
    return getString("message");
  }

  @Override
  public ISimpleRpcServer getServer() {
    return server;
  }

  public boolean isDone() {
    return done;
  }

  public boolean isEqual(IServerRequest request) {
    if (no(request)) return false;
    String url = getUrl().asString();
    String requestUrl = request.getUrl().asString();
    return url.equals(requestUrl);
  }

  public boolean isFailed() {
    return failed;
  }

  @Override
  public boolean isLoaded() {
    return loaded;
  }

  public boolean isSuccess() {
    return data.getBoolean("success");
  }

  public void run() {
    try {
      final String response = getResponseString(getUrl().asString());
      final JSONObject json = json(response).asObject();
      if (EXCEPTION_SESSION_EXPIRED.equals(json.getString(EXCEPTION_ID)))
        onSessionExpiredRun();
      else doLater(new Run() {
        public void run() {
          processOnUIThread(json);
          onProcessDone();
        }
      });
    } catch (final Exception e) {
      doLater(new Run() {
        public void run() {
          requestFailed(e);
          onProcessDone();
        }
      });
    }
  }

  @Override
  public void send() {
    application.getRequestManager().send(this);
  }

  public void setAction(String action) {
    this.action = action;
  }

  protected void doLater(Runnable runnable) {
    Lang.doLater(runnable);
  }

  protected String getException() {
    return getString(EXCEPTION_ID);
  }

  protected String getExceptionDetials() {
    return getString("exception_details");
  }

  protected CharSequence getNumberString(String key) {
    return data.getNumber(key).intValue() + "";
  }

  @Override
  protected String getServerUrl() {
    return server.getServerUrl();
  }

  protected String getString(String key) {
    return data.getString(key);
  }

  protected void onRequestFailed(String message, String details) {
    exceptionMessage = message;
    exceptionDetails = details;
    failed = true;
    fire(eventFailed);
  }

  protected void onRequestFailedOnServer(String excetionId, String exceptionDetails) {
    error("Request Failed", excetionId, exceptionDetails);
    onRequestFailed(excetionId, exceptionDetails);
  }

  protected void onRequestLoaded() {
    loaded = true;
    fire(eventLoaded);
  }

  protected void onSessionExpiredOnUiThread() {
    server.setSession(null);
    application.getRequestManager().postAtFrontOfQueue(ServerRequest.this);
    application.getRequestManager().postAtFrontOfQueue(server.getLogin());
  }

  @Override
  protected void onUrlCreated(UrlBuilder url) {
    fire(urlCreateEvent, url);
  }

  private void onProcessDone() {
    done = true;
    fire(eventDone);
  }

  private void onSessionExpiredRun() {
    doLater(new Run() {
      public void run() {
        onSessionExpiredOnUiThread();
      }
    });
    sleep(3000);
  }

  private void processOnUIThread(final JSONObject json) {
    data = json;
    if (is(getException()))
      onRequestFailedOnServer(getException(), getExceptionDetials());
    else onRequestLoaded();
  }

  private void requestFailed(Exception e) {
    error(e, "Request Failed");
    onRequestFailed(e.getMessage(), Lang.createTraceString(e));
  }

}
